package me.szlx.thing;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public interface Traits extends TraitLet, Iterable<Trait> {
    /**
     * <p>
     * 判断是否匹配指定的标签。如果匹配则返回{@code true}，否则返回{@code false}。
     * </p>
     * <p>
     * 如果指定的标签为{@code null}，则总是返回{@code true}，表示实际上无需进行任何匹配。
     * </p>
     * <p>
     * <p>
     * 匹配是将同时匹配标签的“代码”和“名称”，即使用匹配行为{@link Trait.MatchAction#NAME_AND_VALUE}。
     * </p>
     *
     * @param tag 待匹配的标签。
     * @return 匹配则返回 {@code true}，否则返回 {@code false}。
     * @see #match(TraitLet, Trait.MatchAction)
     */
    default boolean match(TraitLet tag) {
        return match(tag, Trait.MatchAction.NAME_AND_VALUE);
    }

    /**
     * <p>
     * 判断是否匹配指定的标签。如果匹配则返回{@code true}，否则返回{@code false}。
     * </p>
     * <p>
     * 如果指定的标签为{@code null}，则总是返回{@code true}，表示实际上无需进行任何匹配。
     * </p>
     *
     * @param tag    待匹配的标签。
     * @param action 匹配行为。
     * @return 匹配则返回{@code true}，否则返回{@code false}。
     */
    default boolean match(TraitLet tag, Trait.MatchAction action) {
        if (tag == null) {
            return true;
        }
        action = action != null ? action : Trait.MatchAction.NAME_AND_VALUE;

        Trait[] thatTraits = Trait.marshal(tag);

        for (Trait thatTrait : thatTraits) {
            boolean matched = false;
            Iterator<Trait> tagIterator = this.iterator();
            while (!matched && tagIterator.hasNext()) {
                Trait theTrait = tagIterator.next();
                if (theTrait != null) {
                    matched = theTrait.match(thatTrait, action);
                }
            }
            if (matched == false) {
                return false;
            }
        }
        return true;
    }

    default Traits append(TraitLet... tags) {
        if (tags == null || tags.length == 0) {
            return this;
        }

        List<Trait> traitList = Arrays.asList(Trait.marshal(tags));
        Iterator<Trait> tagIterator = this.iterator();
        while (tagIterator.hasNext()) {
            Trait trait = tagIterator.next();
            if (trait != null) {
                traitList.add(trait);
            }
        }
        return new TraitsVO(traitList.toArray(new Trait[0]));
    }

    default Trait ofName(String name) {
        if (name != null) {
            Iterator<Trait> iterator = this.iterator();
            while (iterator.hasNext()) {
                Trait trait = iterator.next();
                if (trait != null && name.equals(trait.getName())) {
                    return trait;
                }
            }
        }
        return null;
    }

    static Traits of(TraitLet... traitLets) {
        return new TraitsVO(traitLets);
    }

    static Traits of(Collection<? extends TraitLet> traitLets) {
        return new TraitsVO(traitLets.toArray(new TraitLet[0]));
    }
}

class TraitsVO implements Traits {
    private Trait[] traits;

    public TraitsVO(TraitLet... tags) {
        traits = Trait.marshal(tags);
    }

    @Override
    public Iterator<Trait> iterator() {
        return new TagIterator(traits);
    }

    private static class TagIterator implements Iterator<Trait> {
        private final Trait[] traits;
        private int currentIndex = 0;

        public TagIterator(Trait[] traits) {
            this.traits = traits;
        }

        public boolean hasNext() {
            return traits == null ? false : this.currentIndex < traits.length;
        }

        public Trait next() {
            return this.traits[this.currentIndex++];
        }

        public void remove() {
            throw new UnsupportedOperationException("不能从标签集合中移除标签");
        }
    }
}